package proxy

import (
	"net/http"

	"gitee.com/xuender/mysql-proxy/pb"
	"github.com/gin-gonic/gin"
	"github.com/lithammer/shortuuid"
	"github.com/xuender/oils/base"
	"golang.org/x/exp/slices"
)

type ConnService struct {
	c *pb.Config
}

func NewConnService(config *pb.Config) *ConnService {
	return &ConnService{c: config}
}

func (p *ConnService) Group(group *gin.RouterGroup) {
	group.GET("", p.GET)
	group.POST("", p.POST)
	group.PUT("add/:id", p.AddUser)
	group.PUT("del/:id", p.DelUser)
	group.PUT(":id", p.PUT)
	group.DELETE(":id", p.DELETE)
}

func (p *ConnService) GET(ctx *gin.Context) {
	ctx.JSON(http.StatusOK, p.c.Conns)
}

func (p *ConnService) PUT(ctx *gin.Context) {
	id := base.Panic1(base.ParseInteger[uint32](ctx.Param("id")))
	conn := &pb.Conn{}
	base.Panic(ctx.Bind(&conn))

	for _, old := range p.c.Conns {
		if old.Id == id {
			old.Name = conn.Name
			old.Address = conn.Address
			old.Charset = conn.Charset
			old.Schema = conn.Schema
			old.Password = conn.Password
			old.Username = conn.Username

			base.Panic(p.c.Save(""))

			break
		}
	}

	ctx.JSON(http.StatusOK, p.c.Conns)
}

func (p *ConnService) DELETE(ctx *gin.Context) {
	id := base.Panic1(base.ParseInteger[uint32](ctx.Param("id")))

	for index, con := range p.c.Conns {
		if con.Id == id {
			p.c.Conns = slices.Delete(p.c.Conns, index, index+1)

			base.Panic(p.c.Save(""))

			break
		}
	}

	ctx.JSON(http.StatusOK, p.c.Conns)
}

func (p *ConnService) POST(ctx *gin.Context) {
	conn := &pb.Conn{}
	base.Panic(ctx.Bind(&conn))

	var max uint32

	for _, conn := range p.c.Conns {
		if max < conn.Id {
			max = conn.Id
		}
	}

	conn.Id = max + 1
	p.c.Conns = append(p.c.Conns, conn)
	base.Panic(p.c.Save(""))

	ctx.JSON(http.StatusOK, p.c.Conns)
}

func (p *ConnService) AddUser(ctx *gin.Context) {
	input := &pb.User{}
	base.Panic(ctx.Bind(input))

	if input.User == "" {
		input.User = ctx.GetString(gin.AuthUserKey)
	}

	id := base.Panic1(base.ParseInteger[uint32](ctx.Param("id")))
	conn := p.getConn(id)

	for _, user := range conn.Users {
		if user.User == input.User {
			ctx.JSON(http.StatusOK, conn)

			return
		}
	}

	conn.Users = append(conn.Users, &pb.User{
		User:     input.User,
		Password: shortuuid.New(),
		Readonly: input.Readonly,
	})

	base.Panic(p.c.Save(""))
	ctx.JSON(http.StatusOK, conn)
}

func (p *ConnService) DelUser(ctx *gin.Context) {
	input := &pb.User{}
	base.Panic(ctx.Bind(input))

	if input.User == "" {
		input.User = ctx.GetString(gin.AuthUserKey)
	}

	id := base.Panic1(base.ParseInteger[uint32](ctx.Param("id")))
	conn := p.getConn(id)

	for index, user := range conn.Users {
		if user.User == input.User {
			conn.Users = slices.Delete(conn.Users, index, index+1)

			base.Panic(p.c.Save(""))
			ctx.JSON(http.StatusOK, conn)

			return
		}
	}

	ctx.JSON(http.StatusOK, conn)
}

func (p *ConnService) getConn(id uint32) *pb.Conn {
	for _, conn := range p.c.Conns {
		if conn.Id == id {
			return conn
		}
	}

	return &pb.Conn{}
}
